package org.zjt.util;


import com.alibaba.fastjson.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.zjt.config.RegisterConfig;
import org.zjt.domain.RpcMsgProto;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Created by Administrator on 2017/4/11.
 */
public class InvokeMethodExecuter {
    private static final Logger LOGGER = LoggerFactory.getLogger(InvokeMethodExecuter.class);

    private static final String DELIMITER = ",";

    public static RpcMsgProto.msg createRpcMsgProto(Method m, Object[] Params  ){
        RpcMsgProto.msg.Builder builder =RpcMsgProto.msg.newBuilder();
        builder.setClassName(m.getDeclaringClass().getName());
        if (Params !=null && Params.length > 0 ){
            List accResult =Arrays.stream(m.getParameterTypes()).map( a -> a.getName() ).collect(Collectors.toList());
            String paramClass = String.join(DELIMITER,accResult);
            builder.setParam(JSONObject.toJSONString(Params));
            builder.setParamClassName(paramClass);
        }
        builder.setMethodName(m.getName());
        return builder.build();
    }

    public static RpcMsgProto.msg resultRpcMsgProto(RpcMsgProto.msg msg,Object result){
        RpcMsgProto.msg.Builder builder =RpcMsgProto.msg.newBuilder();
        builder.setClassName(msg.getClassName());
        builder.setParam(msg.getParam());
        builder.setParamClassName(msg.getParamClassName());
        builder.setMethodName(msg.getMethodName());
        if (result != null){
            builder.setResultClassName(result.getClass().getName());
            builder.setResultJson(JSONObject.toJSONString(result));
        }
        return builder.build();
    }

    public static RpcMsgProto.msg createRpcMsgProto(String FacadeImp,Method m, Object[] Params  ){
        RpcMsgProto.msg.Builder builder =RpcMsgProto.msg.newBuilder();
        builder.setClassName(FacadeImp);
        if (Params !=null && Params.length > 0 ){
            List accResult =Arrays.stream(m.getParameterTypes()).map( a -> a.getName() ).collect(Collectors.toList());
            String paramClass = String.join(DELIMITER,accResult);
            String paramstr = "" ;
            for (Object o : Params)
                paramstr+= JSONObject.toJSONString(o)+ RegisterConfig.PARAMETER_SEPARATOR;
            builder.setParam( paramstr !=null ? paramstr.substring(0,paramstr.length()-1) : null);
            builder.setParamClassName(paramClass);
        }
        builder.setMethodName(m.getName());
        return builder.build();
    }



    public static Object exec(RpcMsgProto.msg msg)throws Exception{
        Class cls = handleSingleClss(msg.getClassName());
        List<Class>  paramClass = handleMethodParamClss( msg.getParamClassName() );
        if (paramClass == null || paramClass.isEmpty() ){
            Method v1 =cls.getDeclaredMethod(msg.getMethodName());
            return v1.invoke(cls.newInstance());
        } else{
            Class[] classes = new Class[paramClass.size()];
            paramClass.toArray(classes);
            Method v1 = cls.getDeclaredMethod(msg.getMethodName(),classes);
            return v1.invoke(cls.newInstance(), handleMethodParam(msg.getParam(),paramClass));
        }
    }


    public static void main(String[] args)throws Exception{
//
       String str ="\"world\"^{\"age\":\"24\",\"id\":1,\"name\":\"ZHANG\"}";
        LOGGER.info(RegisterConfig.PARAMETER_SEPARATOR);
        String[] array = str.split("\\^");
        Arrays.stream(array).forEach(System.out::println);
    }


    //boolean byte char short Int long float double void
    public static List<Class>  handleMethodParamClss(String className)throws Exception{
        className = className != null && !className.trim().equals("") ? className.trim() : null;
        if (className == null) return null ;
        String[] array = className.split(DELIMITER);
        List<Class> classes = new ArrayList<>(array.length);
        for (String c : array){
            switch (c){
                case "int":  classes.add(int.class); break;
                case "double": classes.add( double.class);break;
                case "boolean": classes.add( boolean.class);break;
                case "byte": classes.add( byte.class);break;
                case "char": classes.add( char.class);break;
                case "short": classes.add( short.class);break;
                case "long": classes.add( long.class);break;
                case "float": classes.add( float.class);break;
                case "void": classes.add(void.class);break;
                default:
                    classes.add( Class.forName( c ));
            }
        }
        if(classes.stream().allMatch( a -> a.equals(void.class) ))
            return null;
        return classes;
    }


    public static Class handleSingleClss(String className)throws Exception{
       List<Class> classes = handleMethodParamClss(className);
        Class cl= classes != null && !classes.isEmpty() ? classes.get(0) : null ;
        if (cl == null)
            throw new NullPointerException("class is null");
        return cl;
    }


    public static Object[] handleMethodParam(String params ,List<Class>  paramClass)throws Exception{
        if(params== null || params.trim().equals(""))
            throw new NullPointerException("params is null");
        Object [] objects = new Object[paramClass.size()];
        String[] array = params.split("\\"+RegisterConfig.PARAMETER_SEPARATOR);
        for (int i = 0; i < array.length ; i++) {
            LOGGER.info(array[i]+"             "+paramClass.get(i).getName());
            objects[i] = JSONObject.parseObject(array[i],paramClass.get(i));
        }
        return objects;
    }

}
